iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 16
0
Mobile Development

Android Architecture Components 學習心得筆記系列 第 16

Day 16 Room (一) 介紹與基本使用

  • 分享至 

  • xImage
  •  

Room

Room 是 Google 在 2017 年所提供的組件,專門用來儲存本地端資料,建立 Database,比起原生的 SQLite,需要寫一大堆 SQL 語法,極容易出錯且語法繁瑣,Room 提供了更快速、簡潔的 Database 操作,關鍵的 CRUD 都可以用註解的方式來撰寫,大幅提升了建立本地資料庫的效率。

使用

build.gradle 添加依賴

dependencies {

    //Room
    implementation "android.arch.persistence.room:runtime:2.1.0"
    annotationProcessor "android.arch.persistence.room:compiler:2.1.0"
    testImplementation "android.arch.persistence.room:testing:2.1.0"

Room 由三個部分組成 : EntityDAODatabase

Entity

@Entity(tableName = TABLE_NAME)
class RoomEntity {

    companion object {
        const val TABLE_NAME = "room_entity"
    }

    @PrimaryKey(autoGenerate = true)
    var id: Int = 0
    var name: String = ""

    @NonNull
    @ColumnInfo(name = "timestamp", typeAffinity = ColumnInfo.TEXT)
    var time = ""

    @Ignore
    var ignoreText = ""
}

class 上面以 @Entity(tableName = TABLE_NAME) 標示用來存取的物件
這裡面至少要有一個變數當作 PrimaryKey 用來當作每一個 Entity 物件的唯一識別,
並可透過 autoGenerate 來決定是否自動生成 id。

其中每個欄位名稱默認為變數的命名,如果需要自定義,

需加上註解 @ColumnInfo(name = "timestamp", typeAffinity = ColumnInfo.TEXT)
定義這個欄位的名稱和型別。

如果有不想要存入的變數,加上 @Ignore 註解即可

DAO

@Dao
interface RoomDao {

    @Insert(onConflict = OnConflictStrategy.REPLACE)
    fun insert(item: RoomEntity): Long

    @Insert
    fun insertAll(item: RoomEntity)

    @Query("SELECT * FROM room_entity WHERE name LIKE :name")
    fun findByName(name: String): RoomEntity

    @Query("SELECT * FROM room_entity")
    fun getAll(): List<RoomEntity>

    @Delete
    fun delete(item: RoomEntity)

    @Update
    fun update(item: RoomEntity)
}

interface 上面以 @Dao 標示用來對資料庫操作的介面
CRUD 增刪查改都是透過這個介面來完成。

@Insert(onConflict = OnConflictStrategy.REPLACE) 表示新增物件時和舊物件發生衝突後的處置,
裡面有五個模式可以用,這邊我只簡單做測試這五個模式發生衝突時會發生什麼事,需要深入研究的可以看這邊

  1. REPLACE 蓋掉 (最常用)
  2. ROLLBACK 閃退
  3. ABORT 閃退 (默認)
  4. FAIL 閃退
  5. IGNORE 忽略,還是舊的資料

需要尋找特定欄位符合名稱的就把參數傳進來再用 WHERE "欄位名稱" LIKE :參數名稱查詢

    @Query("SELECT * FROM room_entity WHERE name LIKE :name")
    fun findByName(name: String): RoomEntity

Database

@Database(entities = [(RoomEntity::class)], version = 1)
abstract class RoomDbHelper : RoomDatabase() {

    companion object {
        @Volatile private var instance: RoomDbHelper? = null
        private val LOCK = Any()

        operator fun invoke(context: Context)= instance ?: synchronized(LOCK){
            instance ?: buildDatabase(context).also { instance = it}
        }

        private fun buildDatabase(context: Context) = Room.databaseBuilder(context,
            RoomDbHelper::class.java, "item-list.db").build()
    }

    abstract fun getRoomDao(): RoomDao
}

註解為 @Database 的類別必須繼承 RoomDatabase ,並加上需要儲存的 Entity 類別 和 Version,
這裡用的是 Singleton 寫法,也是官方所推薦的,因為實體的產生很耗資源,而且也不需要多個資料庫實體,所以宣告為 Singleton 即可。

最後來看看如何使用吧
前面建立完三個主要物件後,其他地方的 CRUD 就簡單得多

val db = RoomDbHelper(this)

先把 RoomDbHelper 建立好,這個 this 傳入一個 Context。
Room不允許在主線程做操作,有一個辦法是在 Builder 那邊加入 allowMainThreadQueries()
不過 Kotlin 可以用更優雅的 協程 來完成這件事

Insert
存入一個 id = 3, name = "Wade" 的物件

GlobalScope.launch {

    val user = db.getRoomDao().insert(RoomEntity().apply {
        id = 3
        name = "Wade"
    })
}

Delete
先把要刪掉的那一筆 Query 出來,再直接刪掉就可以了。

GlobalScope.launch {

    val user = db.getRoomDao().findByName("Wade")
    db.getRoomDao().delete(user)
}

其他方法大同小異,就不列出來了

有任何問題或講得不清楚的地方歡迎留言和我討論。

更歡迎留言糾正我任何說錯的地方!

下一篇:Room (二) Query 的詳細用法以及如何升級資料庫版本


上一篇
Day 15 LiveData 介紹與使用
下一篇
Day 17 Room (二) Query 的詳細用法以及如何升級(Migrate)資料庫版本
系列文
Android Architecture Components 學習心得筆記30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言